package com.tc.data.common.holder;

import com.tc.data.common.strategy.table.TableShardingStrategy;
import com.tc.data.common.util.CleanType;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

/**
 * 策略持有者
 */
public class StrategyHolder {
	private static final ThreadLocal<Stack<ShardingStrategy>> REPOSITORY_SHARDING_STRATEGY_STACK = new ThreadLocal<Stack<ShardingStrategy>>();
	private static final ThreadLocal<Map<String, TableShardingStrategy>> TABLE_SHARDING_STRATEGIES = new ThreadLocal<Map<String, TableShardingStrategy>>();
	private static final ThreadLocal<Boolean> AUTOCOMMIT_HOLDER=new ThreadLocal<Boolean>();
	
	public static void setAutocommit(Boolean autocommit) {
		AUTOCOMMIT_HOLDER.set(autocommit);
	}
	
	public static void clearAutocommit() {
		AUTOCOMMIT_HOLDER.remove();
	}
	
	public static Boolean getAutocommit() {
		return AUTOCOMMIT_HOLDER.get();
	}
	
	public static void setRepositoryShardingKey(String key, boolean transaction, CleanType cleanType) {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (stack == null) {
			stack = new Stack<ShardingStrategy>();
		}
		ShardingStrategy strategy = new ShardingStrategy();
		strategy.setRepositoryShardingKey(key);
		strategy.setCleanType(cleanType);
		strategy.setTransaction(transaction);
		stack.push(strategy);
		REPOSITORY_SHARDING_STRATEGY_STACK.set(stack);
	}

	public static String getRepositoryShardingKey() {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (CollectionUtils.isEmpty(stack)) {
			return null;
		}
		return stack.peek().getRepositoryShardingKey();
	}

	public static void removeShardingStrategy(CleanType cleanType) {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (CollectionUtils.isEmpty(stack)) {
			REPOSITORY_SHARDING_STRATEGY_STACK.remove();
			return;
		}

		ShardingStrategy shardingStrategy = stack.peek();
		if (shardingStrategy.getCleanType().equals(cleanType)) {
			stack.pop();
			if (CollectionUtils.isEmpty(stack)) {
				REPOSITORY_SHARDING_STRATEGY_STACK.remove();
			}
		}
	}

	public static void clearDataSourceKey() {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (CollectionUtils.isEmpty(stack)) {
			REPOSITORY_SHARDING_STRATEGY_STACK.remove();
			return;
		}
		// ShardingStrategy strategy = stack.pop();
		// strategy.setDataSourceKey(null);
		// stack.push(strategy);

		ShardingStrategy strategy = stack.peek();
		strategy.setDataSourceKey(null);
		// REPOSITORY_SHARDING_STRATEGY_STACK.set(stack);
	}

	public static void setDataSourceKey(String key) {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (CollectionUtils.isEmpty(stack)) {
			stack = new Stack<ShardingStrategy>();
			ShardingStrategy strategy = new ShardingStrategy();
			strategy.setDataSourceKey(key);
			strategy.setCleanType(CleanType.READWRITE);
			stack.push(strategy);
			REPOSITORY_SHARDING_STRATEGY_STACK.set(stack);
		} else {
			ShardingStrategy strategy = stack.peek();
			strategy.setDataSourceKey(key);
			// stack.push(strategy);
		}
		// REPOSITORY_SHARDING_STRATEGY_STACK.set(stack);
	}

	public static String getDataSourceKey() {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (CollectionUtils.isEmpty(stack)) {
			return null;
		}
		return stack.peek().getDataSourceKey();
	}

	public static TableShardingStrategy getTableShardingStrategy(String key) {
		Map<String, TableShardingStrategy> map = TABLE_SHARDING_STRATEGIES.get();
		if (MapUtils.isEmpty(map)) {
			return null;
		}
		return map.get(key);
	}

	public static Map<String, TableShardingStrategy> getTableShardingStrategies() {
		return TABLE_SHARDING_STRATEGIES.get();
	}

	public static void addTableShardingStrategies(String key, TableShardingStrategy value) {
		Map<String, TableShardingStrategy> map = TABLE_SHARDING_STRATEGIES.get();
		if (map == null) {
			map = new HashMap<String, TableShardingStrategy>();
			TABLE_SHARDING_STRATEGIES.set(map);
		}

		if (!map.containsKey(key)) {
			map.put(key, value);
		}
	}
	
	public static ShardingStrategy getShardingStrategy() {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (CollectionUtils.isEmpty(stack)) {
			return null;
		}
		return stack.peek();
	}
	
	public static boolean hasTransaction() {
		Stack<ShardingStrategy> stack = REPOSITORY_SHARDING_STRATEGY_STACK.get();
		if (CollectionUtils.isEmpty(stack)) {
			return false;
		}
		return stack.peek().getTransaction();
	}

}
